Package org.pushingpixels.flamingo.api.common

Source Code of org.pushingpixels.flamingo.api.common.RichToolTipManager$DismissTimerAction

/*
* Copyright (c) 2005-2010 Flamingo Kirill Grouchnikov. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
*  o Redistributions of source code must retain the above copyright notice,
*    this list of conditions and the following disclaimer.
*    
*  o Redistributions in binary form must reproduce the above copyright notice,
*    this list of conditions and the following disclaimer in the documentation
*    and/or other materials provided with the distribution.
*    
*  o Neither the name of Flamingo Kirill Grouchnikov nor the names of
*    its contributors may be used to endorse or promote products derived
*    from this software without specific prior written permission.
*    
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.pushingpixels.flamingo.api.common;

import java.awt.*;
import java.awt.event.*;
import java.util.List;

import javax.swing.*;

import org.pushingpixels.flamingo.api.common.popup.JPopupPanel;
import org.pushingpixels.flamingo.api.common.popup.PopupPanelManager;
import org.pushingpixels.flamingo.api.ribbon.AbstractRibbonBand;
import org.pushingpixels.flamingo.internal.ui.common.JRichTooltipPanel;

public class RichToolTipManager extends MouseAdapter implements
    MouseMotionListener {
  private Timer initialDelayTimer;

  private Timer dismissTimer;

  private RichTooltip richTooltip;

  private JTrackableComponent insideComponent;

  private MouseEvent mouseEvent;

  final static RichToolTipManager sharedInstance = new RichToolTipManager();

  private Popup tipWindow;

  private JRichTooltipPanel tip;

  private boolean tipShowing = false;

  private static final String TRACKED_FOR_RICH_TOOLTIP = "flamingo.internal.trackedForRichTooltip";

  public static abstract class JTrackableComponent extends JComponent {
    public abstract RichTooltip getRichTooltip(MouseEvent mouseEvent);
  }

  RichToolTipManager() {
    initialDelayTimer = new Timer(750, new InitialDelayTimerAction());
    initialDelayTimer.setRepeats(false);
    dismissTimer = new Timer(20000, new DismissTimerAction());
    dismissTimer.setRepeats(false);
  }

  /**
   * Specifies the initial delay value.
   *
   * @param milliseconds
   *            the number of milliseconds to delay (after the cursor has
   *            paused) before displaying the tooltip
   * @see #getInitialDelay
   */
  public void setInitialDelay(int milliseconds) {
    initialDelayTimer.setInitialDelay(milliseconds);
  }

  /**
   * Returns the initial delay value.
   *
   * @return an integer representing the initial delay value, in milliseconds
   * @see #setInitialDelay
   */
  public int getInitialDelay() {
    return initialDelayTimer.getInitialDelay();
  }

  /**
   * Specifies the dismissal delay value.
   *
   * @param milliseconds
   *            the number of milliseconds to delay before taking away the
   *            tooltip
   * @see #getDismissDelay
   */
  public void setDismissDelay(int milliseconds) {
    dismissTimer.setInitialDelay(milliseconds);
  }

  /**
   * Returns the dismissal delay value.
   *
   * @return an integer representing the dismissal delay value, in
   *         milliseconds
   * @see #setDismissDelay
   */
  public int getDismissDelay() {
    return dismissTimer.getInitialDelay();
  }

  void showTipWindow(MouseEvent mouseEvent) {
    if (insideComponent == null || !insideComponent.isShowing())
      return;
    Dimension size;
    Point screenLocation = insideComponent.getLocationOnScreen();
    Point location = new Point();
    GraphicsConfiguration gc;
    gc = insideComponent.getGraphicsConfiguration();
    Rectangle sBounds = gc.getBounds();
    Insets screenInsets = Toolkit.getDefaultToolkit().getScreenInsets(gc);
    // Take into account screen insets, decrease viewport
    sBounds.x += screenInsets.left;
    sBounds.y += screenInsets.top;
    sBounds.width -= (screenInsets.left + screenInsets.right);
    sBounds.height -= (screenInsets.top + screenInsets.bottom);

    // Just to be paranoid
    hideTipWindow();

    tip = new JRichTooltipPanel(insideComponent.getRichTooltip(mouseEvent));
    tip
        .applyComponentOrientation(insideComponent
            .getComponentOrientation());
    size = tip.getPreferredSize();

    AbstractRibbonBand<?> ribbonBand = (AbstractRibbonBand<?>) SwingUtilities
        .getAncestorOfClass(AbstractRibbonBand.class, insideComponent);
    boolean ltr = tip.getComponentOrientation().isLeftToRight();
    boolean isInRibbonBand = (ribbonBand != null);
    if (isInRibbonBand) {
      // display directly below or above ribbon band
      location.x = ltr ? screenLocation.x : screenLocation.x
          + insideComponent.getWidth() - size.width;
      Point bandLocationOnScreen = ribbonBand.getLocationOnScreen();
      location.y = bandLocationOnScreen.y + ribbonBand.getHeight() + 4;
      if ((location.y + size.height) > (sBounds.y + sBounds.height)) {
        location.y = bandLocationOnScreen.y - size.height;
      }
    } else {
      // display directly below or above it
      location.x = ltr ? screenLocation.x : screenLocation.x
          + insideComponent.getWidth() - size.width;
      location.y = screenLocation.y + insideComponent.getHeight();
      if ((location.y + size.height) > (sBounds.y + sBounds.height)) {
        location.y = screenLocation.y - size.height;
      }
    }

    // Tweak the X location to not overflow the screen
    if (location.x < sBounds.x) {
      location.x = sBounds.x;
    } else if (location.x - sBounds.x + size.width > sBounds.width) {
      location.x = sBounds.x + Math.max(0, sBounds.width - size.width);
    }

    PopupFactory popupFactory = PopupFactory.getSharedInstance();
    tipWindow = popupFactory.getPopup(insideComponent, tip, location.x,
        location.y);
    tipWindow.show();

    dismissTimer.start();
    tipShowing = true;
  }

  void hideTipWindow() {
    if (tipWindow != null) {
      tipWindow.hide();
      tipWindow = null;
      tipShowing = false;
      tip = null;
      dismissTimer.stop();
    }
  }

  /**
   * Returns a shared <code>ToolTipManager</code> instance.
   *
   * @return a shared <code>ToolTipManager</code> object
   */
  public static RichToolTipManager sharedInstance() {
    return sharedInstance;
  }

  /**
   * Registers a component for tooltip management.
   * <p>
   * This will register key bindings to show and hide the tooltip text only if
   * <code>component</code> has focus bindings. This is done so that
   * components that are not normally focus traversable, such as
   * <code>JLabel</code>, are not made focus traversable as a result of
   * invoking this method.
   *
   * @param comp
   *            a <code>JComponent</code> object to add
   * @see JComponent#isFocusTraversable
   */
  public void registerComponent(JTrackableComponent comp) {
    if (Boolean.TRUE.equals(comp
        .getClientProperty(TRACKED_FOR_RICH_TOOLTIP)))
      return;
    comp.addMouseListener(this);
    // commandButton.addMouseMotionListener(moveBeforeEnterListener);
    comp.putClientProperty(TRACKED_FOR_RICH_TOOLTIP, Boolean.TRUE);
  }

  /**
   * Removes a component from tooltip control.
   *
   * @param comp
   *            a <code>JComponent</code> object to remove
   */
  public void unregisterComponent(JTrackableComponent comp) {
    comp.removeMouseListener(this);
    comp.putClientProperty(TRACKED_FOR_RICH_TOOLTIP, null);
  }

  @Override
  public void mouseEntered(MouseEvent event) {
    initiateToolTip(event);
  }

  private void initiateToolTip(MouseEvent event) {
    JTrackableComponent component = (JTrackableComponent) event.getSource();
    // component.removeMouseMotionListener(moveBeforeEnterListener);

    Point location = event.getPoint();
    // ensure tooltip shows only in proper place
    if (location.x < 0 || location.x >= component.getWidth()
        || location.y < 0 || location.y >= component.getHeight()) {
      return;
    }

    // do not show tooltips on components in popup panels that are not
    // in the last shown one
    List<PopupPanelManager.PopupInfo> popups = PopupPanelManager
        .defaultManager().getShownPath();
    if (popups.size() > 0) {
      JPopupPanel popupPanel = popups.get(popups.size() - 1)
          .getPopupPanel();
      boolean ignore = true;
      Component c = component;
      while (c != null) {
        if (c == popupPanel) {
          ignore = false;
          break;
        }
        c = c.getParent();
      }
      if (ignore)
        return;
    }

    if (insideComponent != null) {
      initialDelayTimer.stop();
    }
    // A component in an unactive internal frame is sent two
    // mouseEntered events, make sure we don't end up adding
    // ourselves an extra time.
    component.removeMouseMotionListener(this);
    component.addMouseMotionListener(this);

    insideComponent = component;
    mouseEvent = event;
    initialDelayTimer.start();
  }

  @Override
  public void mouseExited(MouseEvent event) {
    initialDelayTimer.stop();
    if (insideComponent != null) {
      insideComponent.removeMouseMotionListener(this);
    }
    insideComponent = null;
    richTooltip = null;
    mouseEvent = null;
    hideTipWindow();
  }

  @Override
  public void mousePressed(MouseEvent event) {
    hideTipWindow();
    initialDelayTimer.stop();
    insideComponent = null;
    mouseEvent = null;
  }

  @Override
  public void mouseDragged(MouseEvent event) {
  }

  @Override
  public void mouseMoved(MouseEvent event) {
    if (tipShowing) {
      checkForTipChange(event);
    } else {
      // Lazily lookup the values from within insideTimerAction
      insideComponent = (JTrackableComponent) event.getSource();
      mouseEvent = event;
      richTooltip = null;
      initialDelayTimer.restart();
    }
  }

  private void checkForTipChange(MouseEvent event) {
    JTrackableComponent component = (JTrackableComponent) event.getSource();
    RichTooltip newTooltip = component.getRichTooltip(event);

    // is it different?
    boolean isDifferent = (richTooltip != newTooltip);
    if (isDifferent) {
      hideTipWindow();
      if (newTooltip != null) {
        richTooltip = newTooltip;
        initialDelayTimer.restart();
      }
    }
  }

  protected class InitialDelayTimerAction implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      if (insideComponent != null && insideComponent.isShowing()) {
        // Lazy lookup
        if (richTooltip == null && mouseEvent != null) {
          richTooltip = insideComponent.getRichTooltip(mouseEvent);
        }
        if (richTooltip != null) {
          boolean showRichTooltip = true;
          // check that no visible popup is originating in this
          // component
          for (PopupPanelManager.PopupInfo pi : PopupPanelManager
              .defaultManager().getShownPath()) {
            if (pi.getPopupOriginator() == insideComponent) {
              showRichTooltip = false;
              break;
            }
          }

          if (showRichTooltip) {
            showTipWindow(mouseEvent);
          }
        } else {
          insideComponent = null;
          richTooltip = null;
          mouseEvent = null;
          hideTipWindow();
        }
      }
    }
  }

  protected class DismissTimerAction implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      hideTipWindow();
      initialDelayTimer.stop();
      insideComponent = null;
      mouseEvent = null;
    }
  }
}
TOP

Related Classes of org.pushingpixels.flamingo.api.common.RichToolTipManager$DismissTimerAction

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.